<?php
declare(strict_types=1);
/**
 * MineAdmin is committed to providing solutions for quickly building web applications
 * Please view the LICENSE file that was distributed with this source code,
 * For the full copyright and license information.
 * Thank you very much for using MineAdmin.
 *
 * @Author X.Mo<root@imoi.cn>
 * @Link   https://gitee.com/xmo/MineAdmin
 */

namespace Plugin\Message\Service;

use App\Exception\BusinessException;
use App\Http\Common\ResultCode;
use Common\Common;
use Hyperf\Collection\Arr;
use Hyperf\DbConnection\Db;
use Plugin\Alarm\Repository\RdAlarmMsgRepository;
use Plugin\Alarm\Repository\RdAlarmWorkRepository;
use Plugin\Message\Repository\MessageReadRepository;
use Plugin\Message\Repository\MessageRepository;
use Plugin\Message\Enums\MessageTypeEnum;
use App\Service\IService;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

/**
 * 消息表服务类
 */
final class MessageService extends IService
{
    public function __construct(
        protected readonly MessageRepository $repository,
        protected readonly MessageReadRepository $messageReadRepository,
    ) {}

    /**
     * 创建消息的通用方法
     * @param array $data 消息数据
     * @param MessageTypeEnum $type 消息类型枚举
     * @return mixed
     */
    public function createMessage(array $data, MessageTypeEnum $type): mixed
    {
        // 创建消息
        $message = parent::create([
            'type' => $type->value,
            'title' => $data['title'] ?? '',
            'content' => $data['content'] ?? '',
            'extra' => $data['extra'] ?? null,
            'related_id' => $data['related_id'] ?? 0,
            'level' => $data['level'] ?? 1,
        ]);
        
        if ($message) {
            $push_user = Arr::get($data, 'push_user', []);
            
            // 在消息阅读表中为每个用户创建记录
            if (!empty($push_user)) {
                $readData = array_map(fn($user_id) => [
                    'message_id' => $message['id'],
                    'user_id' => $user_id,
                    'type' => $type->value,
                ], $push_user);
                
                $this->messageReadRepository->batchCreate($readData);
            }
            
            return $message;
        }
        
        return false;
    }

    /**
     * 创建预警消息
     * @param array $pushUser
     * @param string $title
     * @param string $content
     * @param array|null $extra
     * @param int $relatedId
     * @param int $level
     * @return mixed
     */
    public function createAlarmMessage(
        array $pushUser,
        string $title = '', 
        string $content = '',
        ?array $extra = null,
        int $relatedId = 0,
        int $level = 1
    ): mixed
    {
        return $this->createMessage([
            'title' => $title,
            'content' => $content,
            'push_user' => $pushUser,
            'extra' => $extra,
            'related_id' => $relatedId,
            'level' => $level,
        ], MessageTypeEnum::ALARM);
    }

    /**
     * 创建反馈消息
     * @param array $pushUser
     * @param string $title
     * @param string $content
     * @param array|null $extra
     * @param int $relatedId
     * @param int $level
     * @return mixed
     */
    public function createCallbackMessage(
        array $pushUser,
        string $title = '', 
        string $content = '',
        ?array $extra = null,
        int $relatedId = 0,
        int $level = 1
    ): mixed
    {
        return $this->createMessage([
            'title' => $title,
            'content' => $content,
            'push_user' => $pushUser,
            'extra' => $extra,
            'related_id' => $relatedId,
            'level' => $level,
        ], MessageTypeEnum::CALLBACK);
    }

    /**
     * 创建系统消息
     * @param array $pushUser
     * @param string $title
     * @param string $content
     * @param array|null $extra
     * @param int $relatedId
     * @param int $level
     * @return mixed
     */
    public function createSystemMessage(
        array $pushUser,
        string $title = '', 
        string $content = '',
        ?array $extra = null,
        int $relatedId = 0,
        int $level = 1
    ): mixed
    {
        return $this->createMessage([
            'title' => $title,
            'content' => $content,
            'push_user' => $pushUser,
            'extra' => $extra,
            'related_id' => $relatedId,
            'level' => $level,
        ], MessageTypeEnum::SYSTEM);
    }
    
    /**
     * 根据类型创建消息
     * @param array $data 消息数据
     * @param int $type 消息类型
     * @return mixed
     */
    public function createMessageByType(array $data, int $type): mixed
    {
        try {
            $enum = MessageTypeEnum::from($type);
        } catch (\ValueError $e) {
            throw new \InvalidArgumentException('Invalid message type');
        }
        
        return $this->createMessage($data, $enum);
    }

    /**
     * 标记消息为已读
     * @param int $messageId 消息ID
     * @param int $userId 用户ID
     * @return bool
     */
    public function markAsRead(int $messageId, int $userId)
    {
        $readRecord = $this->messageReadRepository->getQuery()->where('message_id', $messageId)
            ->where('user_id', $userId)
            ->first();

        if ($readRecord) {
            // 更新已存在的记录
            $readRecord->status = 2;
            $readRecord->read_time = date('Y-m-d H:i:s');
            $readRecord->update(['status' => 2, 'read_time' => date('Y-m-d H:i:s')]);
            return $readRecord;
        } else {
            // 创建新的读取记录
            return $this->messageReadRepository->create([
                'message_id' => $messageId,
                'user_id' => $userId,
                'status' => 2,
                'read_time' => date('Y-m-d H:i:s'),
            ]);
        }
    }

    /**
     * 批量标记消息为已读
     * @param array $messageIds 消息ID数组
     * @param int $userId 用户ID
     * @return bool
     */
    public function markAsReadBatch(array $messageIds, int $userId): bool
    {
        foreach ($messageIds as $messageId) {
            $this->markAsRead($messageId, $userId);
        }
        return true;
    }

    private function getRelatedData(mixed $id, mixed $userId)
    {
        $message = $this->findById($id);
        if (!$message) {
            return [];
        }
        
        $relatedId = $message->related_id;
        // 根据消息类型确定关联关系：
        // 1 - 预警消息关联报警
        // 2 - 反馈消息关联工单
        // 3 - 系统消息无关联
        if ($message->type == 1) {
            // 预警消息关联报警
            try {
                return Common::container()->get(RdAlarmMsgRepository::class)
                    ->getQuery()->whereKey($relatedId)->first();
            } catch (\Throwable $e) {
                return [];
            }
        } else if ($message->type == 2) {
            // 反馈消息关联工单
            try {
                return Common::container()->get(RdAlarmWorkRepository::class)
                    ->findById($relatedId);
            } catch (\Throwable $e) {
                return [];
            }
        }
        // 系统消息或其他类型无关联
        return [];
    }

    public function read(int $id, int $userId)
    {
        $message = $this->findById($id);
        if (!$message) {
            throw new BusinessException(ResultCode::NOT_FOUND, '消息不存在');
        }
        Db::beginTransaction();
        try {
            $this->markAsRead($id, $userId);
            $data = $this->getRelatedData($id, $userId);
            Db::commit();
        } catch (\Throwable $e) {
            Db::rollBack();
            Common::logException(__CLASS__, $e);
            throw new BusinessException(ResultCode::FAIL, '获取数据失败');
        }
        return array_merge($message->toArray(), [
            'related_data' => $data
        ]);
    }

    public function oneKeyRead(int $userId)
    {
        return $this->messageReadRepository->getQuery()->where('user_id', $userId)
            ->where('status', 1)
            ->update(['status' => 2, 'read_time' => date('Y-m-d H:i:s')]);
    }

    public function send(array $all)
    {
        return $this->createMessageByType($all, intval($all['type']));
    }

    public function apiPage(array $params, int $page = 1, int $pageSize = 30): array
    {
        return $this->messageReadRepository
            ->apiPage($params, $page, $pageSize);
    }

    public function apiCountUnread($userId): array
    {
        $unread = $this->messageReadRepository->getQuery()
            ->where('user_id', $userId)
            ->where('status', 1)
            ->pluck('message_id')->toArray();
        if (empty($unread)) {
            return [];
        }
        return $this->repository->getQuery()->whereKey($unread)
            ->get(['id', 'type'])
            ->groupBy('type')
            ->map(function ($item) {
                return count($item);
            })->toArray();

    }
}